#include <base/Chronometer.h>
#include<extra/rgRender.h>

int rg::thread(void *data)
{
	render *thr = static_cast<render*>(data); // Or a reinterpret_cast<> not sure
	SDL_mutexP(thr->m_lock);    /* Lock  the potty */
	thr->loop(thr->m_thControl--, thr->m_cores);  
    SDL_mutexV(thr->m_lock);

	return 0;
}



void rg::render::run()
{
	
	rgInt p;
	SDL_Thread* threads[100];
	m_thControl = m_cores;
	
	for ( p = 0; p < m_cores; ++p)
	{
		threads[p] = SDL_CreateThread( rg::thread, this ); 
	}

	for ( p = 0; p < m_cores; ++p)
	{
		SDL_WaitThread( threads[p], NULL );
	}
}

inline void rg::render::loop(const rgUint16& begin, const rgUint16& step)
{
	rgUint16 px, py;
	rgInt resX = m_pView->getResX();
	rgInt resY = m_pView->getResY();
	rgRay ray(rgPoint(0,0,0), rgVector(0,0,0));
	color c;
	rgReal distance=13;
	material* mat;
	rgPoint hitPoint;
	rgNormal normal;

	for( py = 0; py < resY; ++py)
	{
		for(px = begin; px < resX; px = px + step)
		{ 
			m_pCamera->getRay(px, py, ray);
			
			if( m_pScene->closestObject( ray, hitPoint, normal, distance, mat) )
			{
				c = shade(hitPoint, normal, mat);
				c.check();
				m_pView->drawPoint(px, py, 1, 1, c.getSDL(m_pView->m_pSurface->format));
			}
		}
	}
}

namespace 
{
		bool triIntersect(
			const rgRay& inRay, rgReal& distance, 
			const rgPoint& t0, const rgPoint& t1, const rgPoint& t2)
		{
			
			const rgVector edge1 = t1 - t0;
			const rgVector edge2 = t2 - t0;
			const rgVector pVec = inRay.m_direction ^ edge2;
			rgReal det, t, u, v;

			det = edge1 * pVec;

			// ray is parallel to plane or comes from the back
			if (det < EPSILON) return rgFALSE;

			const rgVector tVec = inRay.m_origin - t0;
			u = tVec * pVec;
			if (u < static_cast<rgReal> (0) || u > det) return rgFALSE;

			const rgVector qVec =  tVec ^ edge1;
			v = inRay.m_direction * qVec;
			if (v < static_cast<rgReal> (0) || u + v > det) return rgFALSE;

			t = edge2 * qVec;
			distance = t / det;
			//m_lastHit = inRay(inRay.maxL);
			
			return rgTRUE;
		}
}

void rg::render::loop2(const rgUint16& begin, const rgUint16& step)
{
	static rgBool firstTime = true;
	//static Chronometer* forChrono = 0;

	//static Chronometer* closestChrono = 0;
	//static Chronometer* sphereChrono = 0;
	//static Chronometer* triChrono = 0;
	//static Chronometer* normalChrono = 0;

	//static Chronometer* shadeChrono =0;
	//static Chronometer* lightsChrono = 0;
	//static Chronometer* lightVChrono = 0;
	//static Chronometer* colorChrono = 0;
	//static Chronometer* ambientChrono = 0;

	//if (firstTime)
	//{
	//	firstTime = false;
	//	forChrono = Chronos::Singleton().add("for: ");

	//	closestChrono = Chronos::Singleton().add("closest: ");
	//	sphereChrono = Chronos::Singleton().add("sphere: ");
	//	triChrono = Chronos::Singleton().add("tri: ");
	//	normalChrono = Chronos::Singleton().add("normal: ");

	//	shadeChrono = Chronos::Singleton().add("shade: ");
	//	lightsChrono =  Chronos::Singleton().add("lights: "); 
	//	ambientChrono = Chronos::Singleton().add("ambient: ");
	//	lightVChrono  =  Chronos::Singleton().add("lightV: ");
	//	colorChrono  =  Chronos::Singleton().add("color: ");
	//}
	//else
	//{
	//	closestChrono->reset();
	//	sphereChrono->reset();
	//	triChrono->reset();
	//	normalChrono->reset();

	//	shadeChrono->reset();
	//	lightsChrono->reset();
	//	ambientChrono->reset();
	//	lightVChrono->reset();
	//	colorChrono->reset();
	//}

	rgUint16 px, py;
	const rgInt resX = m_pView->getResX();
	const rgInt resY = m_pView->getResY();
	rgRay ray(rgPoint(0,0,0), rgVector(0,0,0));
	color c;
	rgReal distance=13;
	material* mat;
	rgPoint hitPoint;
	rgNormal normal;

	m_pCamera->updateCamera();
	const rgVector dX = m_pCamera->m_x;
	const rgVector dY = m_pCamera->m_y;

	rgPoint p = m_pCamera->m_basePoint;
	ray.setOrigin(m_pCamera->m_c2w.m_matrix.m_a03, m_pCamera->m_c2w.m_matrix.m_a13, m_pCamera->m_c2w.m_matrix.m_a23);
	ray.setDirection(p - ray.m_origin);
	
	//forChrono->start();

	for( py = 0; py < resY; ++py)
	{
		for(px = 0; px < resX; ++px)
		{
			rgBool isHitSome = m_pScene->closestObject( ray, hitPoint, normal, distance, mat);
			if( isHitSome )
			{
				c = shade(hitPoint, normal, mat);
				//c.check();

				//drawChrono->start();
				//m_pView->drawPoint(px, py, 1, 1, c.getSDL(m_pView->m_pSurface->format));
				m_pView->DrawPixel2( c.getSDL(m_pView->m_pSurface->format), px, py);
				//drawChrono->lapse();
			}
			//updXChrono.start();
			p+=dX;
			ray.setDirection(p - ray.m_origin);
			ray.m_direction.normalizeMe();
			//updXChrono.lapse();
		}
		//updYChrono.start();
		p-=resX * dX;
		p += dY;
		ray.setDirection(p - ray.m_origin);
		ray.m_direction.normalizeMe();
		//updYChrono.lapse();
	}
	//forChrono->stop();
}